package com.milling.quartz.service;

import com.alibaba.fastjson2.JSONObject;
import com.milling.business.BusinessConstants;
import com.milling.business.GlobalVariable;
import com.milling.business.domain.WmsNeedleSortting;
import com.milling.business.domain.WmsSortingInstockHistory;
import com.milling.business.service.IWmsNeedleSorttingService;
import com.milling.business.service.IWmsSortingInstockHistoryService;
import com.milling.common.core.redis.RedisCache;
import com.milling.common.utils.SocketUtils;
import com.milling.common.utils.StringUtils;
import com.milling.common.utils.http.WmsApiUtils;
import com.milling.common.utils.modbus.ModbusServiceFactory;
import com.milling.common.utils.modbus.ModbusTcpService;
import com.milling.common.utils.uuid.UUID;
import com.milling.framework.websocket.AlertConfirmWebSocketHandler;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;

@Configuration
@ConditionalOnProperty(
        name = "mac.type",
        havingValue = "9",
        matchIfMissing = false // 当配置缺失时不加载
)
//上料服务XXXXXXXXX
@Component
public class SortingTasks {

    private static final Logger logger = LoggerFactory.getLogger(SortingTasks.class);

    @Value("${wcs.tcp.macCode}")
    private String macCode; // 从配置文件或命令行参数中读取

    // 从参数中读取IP、端口、slaveId和连接池大小
    @Value("${modbus.sorting.host:192.168.237.178}")
    private String host; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.port:502}")
    private int port; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.poolSize:5}")
    private int poolSize; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.slaveId:1}")
    private int slaveId;


    @Value("${sorting.scanner.ip}")
    private String sortingScannerIp;

    @Value("${sorting.scanner.instockip}")
    private String instockIp;

    @Value("${sorting.scanner.port}")
    private int sortingScannerPort;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IWmsNeedleSorttingService wmsNeedleSorttingService;

    @Autowired
    private IWmsSortingInstockHistoryService wmsSortingInstockHistoryService;

    @Autowired
    private AlertConfirmWebSocketHandler webSocketHandler;

    // 获取Modbus服务实例
    private ModbusTcpService modbusTcpService;

    @PostConstruct
    public void init() {
        // 初始化 Modbus 服务
        modbusTcpService = ModbusServiceFactory.getModbusService(host, port, poolSize);
        logger.info("SortingTasks Modbus服务初始化完成 - {}:{}", host, port);

        // 初始化扫码器连接
//        initConnection();
    }
//    @Autowired
//    private ModbusUtil modbusUtil;

    // 每500毫秒执行一次
    @Scheduled(fixedRate = 2000)
    public void executeTask() {
        // 这里添加你的业务逻辑
//        logger.info("定时任务执行，间隔0.5秒");

//            int registerAddress = 550;
        int startAddress = 5000;
        int numberOfRegisters = 40;
        short[] values = new short[numberOfRegisters];
        try {
//            int fullBoxPlace = modbusTcpService.readHoldingRegister(slaveId, 5008);
//            logger.info("fullBoxPlace: " + fullBoxPlace);

            // 示例：读取单个保持寄存器
            short[] numbers = new short[numberOfRegisters];
            // 示例：读取多个保持寄存器
            values = modbusTcpService.readHoldingRegisters(slaveId, startAddress, numberOfRegisters);
//            wmsNeedleSorttingService.fixSorttingNeedleBox();
        } catch (ModbusTransportException e) {
            logger.error("读取寄存器地址  失败");
            e.printStackTrace();
        } catch (Exception e) {
            logger.error("读取寄存器地址  失败");
            e.printStackTrace();
        }

        for (int i = 0; i < values.length; i++) {
            if(values[i] > 0) {//需要复位
                onRegisterChange(startAddress + i);
            }
        }

    }

    public void onRegisterChange(int registerAddress) {
        try {
            switch (registerAddress) {
                case 5000://12个盒子扫码动作
                    try {
                        SocketUtils socketUtils = new SocketUtils(sortingScannerIp, sortingScannerPort);
                        socketUtils.sendMessage("start");
                        socketUtils.disconnect();
                        socketUtils.destroy();
//                            Thread.sleep(5);
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("SortingScanner sendMessage Fail");
                        modbusTcpService.writeHoldingRegister(slaveId, 5000, 1000);
                    }
                    break;
                case 5003:
                    /*int fullBoxPlace = modbusTcpService.readHoldingRegister(slaveId, 5008);
                    if(fullBoxPlace > 0) {
                        //分拣时，满盒下料，PLC给D5008写入满盒位置，D5003空盒位置；PC写入D5002盒子样式
                        //在此判断下料的是大钻还是中小钻，然后写入5002 ？
                        modbusTcpService.writeHoldingRegister(slaveId, 5002, 1000);
                    }*/
                    break;
                case 5004: //空盒放入完成信号
                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC,空盒上料完成OK");
                    process5004();
                    //继续补空盒
                    break;
                case 5006: //确定针盒排出完成
                    /*int boxCount = modbusTcpService.readHoldingRegister(slaveId,516);
                    logger.info("PLC通知PC下料针盒数\t当 D515 >= N 时，PLC禁止下料，处理完成后PC进行清零，总下料" + boxCount +"盒");
                    modbusTcpService.writeHoldingRegister(slaveId, 516, 0);*/
//                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC下料针盒数");
//                    D516	PLC通知PC下料针盒数	当 D515 >= N 时，PLC禁止下料，处理完成后PC进行清零
                    break;
                case 5009: //满盒下料完成   PC给5003、5009清0
                    handleRegisterChange(modbusTcpService, registerAddress, "满盒下料完成");
                    modbusTcpService.writeHoldingRegister(slaveId, 5003, 0);

                    break;
                case 5011: //1:50针同型号下料完成, PC清0
//                    logger.info("[PLC]50针同型号下料完成, PC清0，下料钻针尺寸：" + GlobalVariable.GLOBAL_DRILL_SIZE);
                    logger.info("[PLC]50针同型号下料完成, PC清0，下料钻针尺寸：" + getStringCache(GlobalVariable.GLOBAL_DRILL_SIZE));
//                    String drillinfo = GlobalVariable.GLOBAL_DRILL_INFO;
                    String drillinfo = getStringCache(GlobalVariable.GLOBAL_DRILL_INFO);

                    String drillSize2 = drillinfo.substring(0, 4);
                    String drillType = drillinfo.substring(4, 5);
                    String drillGrindCount = drillinfo.substring(7, 8);
                    try {
                        WmsSortingInstockHistory wmsSortingInstockHistory = new WmsSortingInstockHistory();
                        wmsSortingInstockHistory.setDrillInfo(drillinfo);
                        wmsSortingInstockHistory.setDrillCount(new Long(50));
                        wmsSortingInstockHistory.setDrillSize(drillSize2);
                        wmsSortingInstockHistory.setDrillType(drillType);
                        wmsSortingInstockHistory.setDrillGrindCount(new Long(drillGrindCount));

                        wmsSortingInstockHistory.setDrillEdge("1");
                        wmsSortingInstockHistory.setDrillFactory("1");

                        wmsSortingInstockHistory.setCreateTime(new Date());
                        wmsSortingInstockHistory.setCreateBy("Sorting FULL");
                        wmsSortingInstockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_WAIT);//待入库

//        wmsSortingInstockHistory.setDrillInfo(wmsNeedleSorttingDB.getDrillInfo().replace("D", "9"));

                        wmsSortingInstockHistoryService.insertWmsSortingInstockHistory(wmsSortingInstockHistory);
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("50只同料针下料，预记录钻针信息失败" + e.toString());
                    }

                    modbusTcpService.writeHoldingRegister(slaveId, 5015, new Integer(GlobalVariable.GLOBAL_DRILL_SIZE));
//                    GlobalVariable.GLOBAL_DRILL_SIZE = "0";
//                    GlobalVariable.GLOBAL_DRILL_INFO = "";
                    redisCache.setCacheObject("GLOBAL_DRILL_SIZE", "0");
                    redisCache.setCacheObject("GLOBAL_DRILL_INFO", "");
                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC，50针同型号下料完成");
                    break;
/*
                case 5013: //5013 = 6 空盒上料
                    int blankProcess = modbusTcpService.readHoldingRegister(slaveId,5013);
                    if(blankProcess == 6) {
                        handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC，50针同型号下料完成");
                    }
                    break;
*/
//                case 5016: //分拣机放行许可， 0不能放行，1运行放行
//                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC，分拣机允许放行");
//                    break;
                case 5020://清洗完成，扫码
                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC，清洗完成，并送出入前库输送带");
                    try {
                        SocketUtils socketUtils = new SocketUtils(instockIp, sortingScannerPort);
                        socketUtils.sendMessage("start");
                        socketUtils.disconnect();
                        socketUtils.destroy();
//                            Thread.sleep(5);
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("SortingScanner sendMessage Fail");
                        modbusTcpService.writeHoldingRegister(slaveId, 5021, 2);
                    }
                    break;
//                case 5020: //PLC通知PC，清洗完成，并送出入前库输送带
//                    //通知WMS下料信息
//                    handleRegisterChange(modbusTcpService, registerAddress, "PLC通知PC，清洗完成，并送出入前库输送带");
//                    process5020();          //通知邓工即将入库的钻针信息
//                    break;
                case 5023: //分拣满盒下料完成，异常下料完成	PLC写1，由PC清0
                    //D5015		告知PLC满盒下料钻针尺寸
                    //通知WMS下料信息
                    handleRegisterChange(modbusTcpService, registerAddress, "分拣满盒下料完成，异常下料完成");
                    break;
                case 5024: //PLC告知PC第几盒下料
                    int boxs = modbusTcpService.readHoldingRegister(slaveId,5024);
                    logger.info("[PLC]PLC告知PC第几盒下料：" + boxs);

                    int drillCounts = modbusTcpService.readHoldingRegister(slaveId,5900+(boxs-1));
                    logger.info("[PLC]PC读取寄存器地址，获取下料钻针数量：" + drillCounts);

                    //刷缓存，同步钻针数量
                    wmsNeedleSorttingService.sysncNeedleSortingStatus();

                    //换盒默认成盅盒
                    logger.info("[PLC]通知PLC换盒，取成盅盒");
                    modbusTcpService.writeHoldingRegister(slaveId, 5002, 1);

                    String drillSize = process5024(boxs, drillCounts);
                    //D5015		告知PLC满盒下料钻针尺寸
                    modbusTcpService.writeHoldingRegister(slaveId, 5015, new Integer(drillSize));
                    //PLC告知PC第几盒下料，清0
                    handleRegisterChange(modbusTcpService, registerAddress, "PLC告知PC，第几盒满盒下料");

                    //刷缓存，同步钻针数量
                    wmsNeedleSorttingService.sysncNeedleSortingStatus();

                    break;
                case 5029: //PLC告知PC托盘分拣完成	PLC写1，由PC清0
                    handleRegisterChange(modbusTcpService, registerAddress, "当前托盘分拣完成");

                    String alertMessage = "{\"type\":\"alert\",\"title\":\"提示信息\",\"content\":\"当前托盘已分拣完成，需要继续分拣吗？\",\"buttons\":{\"continueSorting\":\"继续\",\"completeSorting\":\"结束\"}}";
                    webSocketHandler.sendAlert(alertMessage);
                    logger.info("[" + new Date() + "] 是否继续分拣提示信息已发送");
                    break;
            }
        } catch (ModbusTransportException e) {
            e.printStackTrace();
            logger.error("写入寄存器地址 "+registerAddress+" 失败");
//            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理寄存器变化逻辑
     *
     * @param modbusTcpService Modbus TCP 服务
     * @param registerAddress  寄存器地址
     * @param description     寄存器描述
     * @throws ModbusTransportException Modbus通信异常
     */
    private void handleRegisterChange(ModbusTcpService modbusTcpService, int registerAddress, String description)
            throws ModbusTransportException {
        modbusTcpService.writeHoldingRegister(slaveId, registerAddress, 0);
        logger.info("Handled register address {}: {}", registerAddress, description);
    }

    private JSONObject genPostData(WmsSortingInstockHistory instockHistory) {
        String drillDirection = "1";    //钻针方向 倒插
        String grindStatus = "0";    //研磨状态 待磨
        String boxType = "01";    //针盒类型 成盅盒
        String m_Drill_Status = calcDrillStatus(drillDirection, grindStatus, boxType);
        String m_Drill_Kepp = "0"; //保留位

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("MacCode", "B001");
        jsonObject.put("TransCode", instockHistory.getTransCode());
        jsonObject.put("Drillinfo", "");
        jsonObject.put("m_Drill_Info", instockHistory.getDrillInfo());
        jsonObject.put("m_Drill_Size", instockHistory.getDrillSize());
        jsonObject.put("m_Drill_Type", instockHistory.getDrillType());
        jsonObject.put("m_Drill_Edge", instockHistory.getDrillEdge());
        jsonObject.put("m_Drill_Factory", instockHistory.getDrillFactory());
        jsonObject.put("m_Drill_Count", instockHistory.getDrillCount().toString());//转换类型
        jsonObject.put("m_Drill_GrindCount", instockHistory.getDrillGrindCount().toString());//转换类型
        jsonObject.put("m_Drill_Status", m_Drill_Status);
        jsonObject.put("m_Drill_Kepp", m_Drill_Kepp);
        jsonObject.put("Timestamp", instockHistory.getUpdateTime());
        return jsonObject;
    }

    private void process5004() {
        try {
            WmsNeedleSortting wmsNeedleSortting = new WmsNeedleSortting();
            wmsNeedleSortting.setStatus(BusinessConstants.SORTTING_NEEDLE_STATUS_FEEDINGBOX);
            wmsNeedleSortting.setType(BusinessConstants.SORTTING_NEEDLE_TYPE_SORTTING);
            List<WmsNeedleSortting> wmsNeedleSorttingList = wmsNeedleSorttingService.selectWmsNeedleSorttingList(wmsNeedleSortting);
            if(wmsNeedleSorttingList.size() > 0) {
                wmsNeedleSortting = wmsNeedleSorttingList.get(0);
                wmsNeedleSorttingService.changeNeedleStatus(wmsNeedleSortting.getNeedleId(), BusinessConstants.SORTTING_NEEDLE_STATUS_NORMAL);//修改状态位 空盒上料中
                logger.info("[PLC]开始空盒上料完成");
                wmsNeedleSorttingService.fixSorttingNeedleBox();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void process5020() {
        try {
            WmsSortingInstockHistory instockHistory = new WmsSortingInstockHistory();
            instockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_WAIT);
            List<WmsSortingInstockHistory> instockHistoryList = wmsSortingInstockHistoryService.selectWmsSortingInstockHistoryList(instockHistory);
            if(null != instockHistoryList && instockHistoryList.size() > 0) {
                WmsSortingInstockHistory updateInstockHistory = instockHistoryList.get(0);
                logger.info("入库针盒记录： " + updateInstockHistory.getId().toString());
                //写入请求包 及 交易码
                String transCode = UUID.randomUUID().toString();
                updateInstockHistory.setTransCode(transCode);
                updateInstockHistory.setUpdateTime(new Date());
                JSONObject jsonObject = genPostData(updateInstockHistory);
                updateInstockHistory.setReqBody(jsonObject.toString());
                updateInstockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_INSTOCKING);//待入库
                wmsSortingInstockHistoryService.updateWmsSortingInstockHistory(updateInstockHistory);

                WmsApiUtils wmsApiUtils = new WmsApiUtils();
                String result = wmsApiUtils.sortingInStock(jsonObject.toString());
                if(StringUtils.isNotEmpty(result)) {
                    JSONObject jsonObject2 = JSONObject.parseObject(result);
                    // 提取顶层字段
                    String code = jsonObject2.getString("Code");
                    String message = jsonObject2.getString("Message");

                    if("0".equals(code)) {
                        logger.info("通知WMS分拣入库钻针信息成功：" + message);
                    } else {
                        logger.error("通知WMS分拣入库钻针信息失败，错误信息：" + message);
                    }
                } else {
                    logger.error("通知WMS分拣入库钻针信息失败，返回结果为空");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String process5024(int boxs, int drillCounts) {
        try {
            WmsNeedleSortting wmsNeedleSorttingDB = wmsNeedleSorttingService.selectWmsNeedleSorttingByNeedleId(new Long(boxs));

//        int drillCounts = modbusTcpService.readHoldingRegister(slaveId,5900+boxs);
            String drillDirection = "1";    //钻针方向 倒插
            String grindStatus = "0";    //研磨状态 待磨
            String boxType = "01";    //针盒类型 成盅盒
            String m_Drill_Status = calcDrillStatus(drillDirection, grindStatus, boxType);
            String m_Drill_Kepp = "0"; //保留位

            String drillSize = wmsNeedleSorttingDB.getDrillSize();
            String drillType = wmsNeedleSorttingDB.getDrillType();
            String drillEdge = wmsNeedleSorttingDB.getDrillEdge();
            String drillFactory = wmsNeedleSorttingDB.getDrillFactory();
            String drillGrindCount = wmsNeedleSorttingDB.getDrillGrindCount().toString();
//        String drillInfo = drillSize + drillType + "11" + drillGrindCount + "D500";
            String drillInfoO = drillSize + drillType + drillEdge + drillFactory + drillGrindCount + m_Drill_Status + drillCounts + m_Drill_Kepp;
            logger.info("分拣入库 钻针信息：" + drillInfoO);
            WmsSortingInstockHistory wmsSortingInstockHistory = new WmsSortingInstockHistory();
            wmsSortingInstockHistory.setDrillCount(new Long(drillCounts));
            wmsSortingInstockHistory.setDrillSize(wmsNeedleSorttingDB.getDrillSize());
            wmsSortingInstockHistory.setDrillType(wmsNeedleSorttingDB.getDrillType());
            wmsSortingInstockHistory.setDrillEdge(wmsNeedleSorttingDB.getDrillEdge());
            wmsSortingInstockHistory.setDrillFactory(wmsNeedleSorttingDB.getDrillFactory());
            wmsSortingInstockHistory.setDrillGrindCount(wmsNeedleSorttingDB.getDrillGrindCount());
            wmsSortingInstockHistory.setCreateTime(new Date());
            wmsSortingInstockHistory.setStatus(BusinessConstants.SORTING_INSTOCK_STATUS_WAIT);//待入库

            wmsSortingInstockHistory.setDrillInfo(drillInfoO);
            wmsSortingInstockHistory.setCreateBy("Sorting MIX");
//        wmsSortingInstockHistory.setDrillInfo(wmsNeedleSorttingDB.getDrillInfo().replace("D", "9"));

            wmsSortingInstockHistoryService.insertWmsSortingInstockHistory(wmsSortingInstockHistory);

//        String drillSize = drillInfo.substring(0, 4);

            logger.info("[PLC]PLC告知PC第几盒下料" + boxs + " ，料号：" + drillInfoO + " 钻针尺寸：" + drillSize);
            return drillSize;
            //D5015		告知PLC满盒下料钻针尺寸
//        modbusTcpService.writeHoldingRegister(slaveId, 5015, new Integer(drillSize));

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("获取下料钻针信息失败，分拣入库失败");
            return "";
        }
    }

    private String calcDrillStatus(String drillDirection, String grindStatus, String boxType) {
        String m_Drill_Status = "0"; // 初始值根据需求设置
        String drillStatus = drillDirection  + grindStatus + boxType; //拼接字符串 钻针方向 + 研磨状态 + 针盒类型
        switch (drillStatus) {
            case "0000":
                m_Drill_Status = "0";
                break;
            case "0001":
                m_Drill_Status = "1";
                break;
            case "0010":
                m_Drill_Status = "2";
                break;
            case "0011":
                m_Drill_Status = "3";
                break;
            case "0100":
                m_Drill_Status = "4";
                break;
            case "0101":
                m_Drill_Status = "5";
                break;
            case "0110":
                m_Drill_Status = "6";
                break;
            case "0111":
                m_Drill_Status = "7";
                break;
            case "1000":
                m_Drill_Status = "8";
                break;
            case "1001":
                m_Drill_Status = "9";
                break;
            case "1010":
                m_Drill_Status = "A";
                break;
            case "1011":
                m_Drill_Status = "B";
                break;
            case "1100":
                m_Drill_Status = "C";
                break;
            case "1101":
                m_Drill_Status = "D";
                break;
            case "1110":
                m_Drill_Status = "E";
                break;
            case "1111":
                m_Drill_Status = "F";
                break;
            default:
                logger.error("未知的钻探状态，无效的参数");
                // 可添加默认情况的处理逻辑
                break;
        }
        return m_Drill_Status;
    }

/*    private void initConfig() {
        GlobalVariable.plc501Value = 0;
        GlobalVariable.startValue = 0;
        GlobalVariable.writeHolesFlag = false;
        GlobalVariable.plc502Value = 0;
        GlobalVariable.CONFIG_TRAY = 0;
        GlobalVariable.CONFIG_BOX_ID = 0;
        GlobalVariable.CONFIG_BOX_CODE = new String[16];
    }*/

    private int getIntCache(String key) {
        return redisCache.getCacheObject(key) == null ? 0 : (int) redisCache.getCacheObject(key);
    }

    private String getStringCache(String key) {
        return redisCache.getCacheObject(key) == null ? "" : (String) redisCache.getCacheObject(key);
    }


}
